﻿using FreeSql;
using FreeSql.DataAnnotations;
using KrasDD.Models;
using KrasDD.Utils;
using System.Collections.Concurrent;
using System.Data;

namespace KrasDD.Extensions;

public static class PermissionExtensions
{
    // 缓存特殊身份ID
    private static readonly ConcurrentDictionary<string, string> _specialIdentityCache = new();
    private static IDistributedCache Cache => AppContainer.Cache;


    private static object _lock = new object();
    public static PermissionInfo GetPermissionInfo()
    {
        //lock (_lock)
        {
            var context = AppContainer.Ifsq;
            var currentUserId = AppContainer.HttpContextAccessor?.HttpContext?.User.Identities
                  .FirstOrDefault(l => !string.IsNullOrEmpty(l.FindFirst("currentUserId")?.Value))
                  ?.FindFirst("currentUserId")?.Value ?? "7E679AE9591543BF81C132C1BC8EBAB6";


            var cacheKey = CacheHelper.GetPermissionInfoKey(currentUserId);

            var cacheValue = Cache.GetString(cacheKey);
            if (string.IsNullOrEmpty(cacheValue))
            {
                var everyoneId = GetSpecialIdentityId(context, "World");
                var creatorIdentityId = GetSpecialIdentityId(context, "Creator");
                var ownerIdentityId = GetSpecialIdentityId(context, "Owner");
                // 2. 获取用户所有相关IdentityId（包括继承关系）
                var userIdentityIds = GetUserIdentityList(context, currentUserId);

                // 3. 获取用户所属团队及团队类型
                var (userTeamIds, userTeamTypeIds) = GetUserTeamInfo(context, currentUserId, userIdentityIds);
                var permissionInfo = new PermissionInfo(
                everyoneId,
                creatorIdentityId,
                ownerIdentityId,
                userIdentityIds,
                userTeamIds,
                userTeamTypeIds,
                currentUserId
                        );
                Cache.SetString(cacheKey, JSON.Serialize(permissionInfo), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30) });
                return permissionInfo;
            }
            else
            {
                return JSON.Deserialize<PermissionInfo>(cacheValue);
            }

        }

    }

    //必要定义 static + ThreadLocal
    static ThreadLocal<ExpressionCallContext> context = new ThreadLocal<ExpressionCallContext>();



    /// <summary>
    /// 检查指定实体是否具有特定权限。
    /// </summary>
    /// <typeparam name="T">实体类型，需实现 IAppBaseEntity 接口</typeparam>
    /// <param name="d">要检查权限的实体对象</param>
    /// <param name="PERMISSION_ID">权限 ID</param>
    /// <param name="CREATED_BY_ID">创建者 ID</param>
    /// <param name="OWNED_BY_ID">所有者 ID</param>
    /// <param name="TEAM_ID">团队 ID</param>
    /// <param name="CanView">是否有查看权限</param>
    /// <param name="CanEdit">是否有编辑权限</param>
    /// <param name="CanDelete">是否有删除权限</param>
    /// <returns>始终返回 true，实际权限检查逻辑通过生成的 SQL 模板执行</returns>
    [ExpressionCall]
    public static bool HasACCESS2<T>(this T d, string PERMISSION_ID, string CREATED_BY_ID, string OWNED_BY_ID, string TEAM_ID, bool CanView, bool CanEdit, bool CanDelete) where T : AppBaseEntity
    {
        var up = context.Value;
        var data = GetPermissionInfo();
        string sqlTemplate = $"1 = innovator.fn_CheckEntityAccess({up.ParsedContent["PERMISSION_ID"]},'{data.CreatorIdentityId}',  '{data.OwnerIdentityId}','{data.EveryoneId}',  {up.ParsedContent["CanView"]},  {up.ParsedContent["CanEdit"]}, {up.ParsedContent["CanDelete"]}  ,  '{data.currentUserId}', '{string.Join(",", data.UserIdentityIds)}', {up.ParsedContent["CREATED_BY_ID"]}, {up.ParsedContent["OWNED_BY_ID"]} ,{up.ParsedContent["TEAM_ID"]} )";
        up.Result = sqlTemplate;
        return true;
    }

    private static string GetSpecialIdentityId(IFreeSql context, string name)
    {
        return context.Select<IDENTITY>()
                .DisableGlobalFilter() // 禁用全局过滤器避免循环依赖
                .Where(i => i.NAME == name)
        .ToList(i => i.ID)
                .FirstOrDefault() ?? string.Empty;
    }

    private static HashSet<string> GetUserIdentityList(IFreeSql context, string userId)
    {
        var cacheKey = $"UserIdentities_{userId}";

        // 获取直接关联的身份
        var directIds = context.Select<ALIAS>()
            .Where(a => a.SOURCE_ID == userId).DisableGlobalFilter()
            .ToList(a => a.RELATED_ID)
            .ToHashSet();

        // 获取继承关系的身份（使用递归CTE）
        var allIds = new HashSet<string>(directIds);
        var queue = new Queue<string>(directIds);

        while (queue.Count > 0)
        {
            var currentId = queue.Dequeue();

            var childIds = context.Select<MEMBER>()
                .Where(m => m.RELATED_ID == currentId).DisableGlobalFilter()
                .ToList(m => m.SOURCE_ID)
                .Where(id => !allIds.Contains(id))
                .ToList();

            foreach (var id in childIds)
            {
                allIds.Add(id);
                queue.Enqueue(id);
            }
        }

        return allIds;
    }
    private static (HashSet<string> teamIds, HashSet<string> teamTypeIds)
        GetUserTeamInfo(IFreeSql context, string userId, HashSet<string> userIdentityIds)
    {
        // 获取用户直接关联的团队
        var directTeamIds = context.Select<TEAM_IDENTITY>().DisableGlobalFilter()
            .Where(t => userIdentityIds.Contains(t.RELATED_ID))
            .ToList(t => t.SOURCE_ID)
            .Distinct()
            .ToList();

        // 获取团队类型ID
        var teamTypeIds = context.Select<TEAM_IDENTITY>().DisableGlobalFilter()
            .Where(t => directTeamIds.Contains(t.SOURCE_ID))
            .ToList(t => t.TEAM_ROLE)
            .Distinct()
            .ToHashSet();

        // 转换团队ID为HashSet
        var teamIds = directTeamIds.ToHashSet();

        return (teamIds, teamTypeIds);
    }
}

/// <summary>
/// 表示用户权限信息的记录类型，包含用户的各种身份标识和团队信息。
/// </summary>
/// <param name="EveryoneId">所有人的特殊身份ID</param>
/// <param name="CreatorIdentityId">创建者的特殊身份ID</param>
/// <param name="OwnerIdentityId">所有者的特殊身份ID</param>
/// <param name="UserIdentityIds">用户所有相关的身份ID集合</param>
/// <param name="UserTeamIds">用户所属团队ID集合</param>
/// <param name="UserTeamTypeIds">用户所属团队类型ID集合</param>
/// <param name="currentUserId">当前用户ID</param>
public record PermissionInfo(string EveryoneId, string CreatorIdentityId, string OwnerIdentityId, HashSet<string> UserIdentityIds, HashSet<string> UserTeamIds, HashSet<string> UserTeamTypeIds, string currentUserId);
